package com.leyou.auth.service;

import com.leyou.auth.config.JwtProperties;
import com.leyou.common.auth.entity.Payload;
import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.auth.utils.RsaUtils;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.CookieUtils;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.UserDTO;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class AuthService {

    @Autowired
    private UserClient userClient;
    @Autowired
    private JwtProperties prop;

//    //公钥存放路径
//    private String publicKeyPath = "F:\\itcast-work\\heima-tianjin-2\\ssh\\id_rsa.pub";
//    //        私钥存放路径
//    private String privateKeyPath = "F:\\itcast-work\\heima-tianjin-2\\ssh\\id_rsa";
    /**
     * 用户登录
     * @param userName
     * @param passWord
     * @return
     */
    public void login(String userName, String passWord, HttpServletResponse response) {
        try {
            //      远程调用user ，验证用户名和密码
            UserDTO userDTO = userClient.queryUser(userName, passWord);
//        构造payload中的用户自描述信息
            UserInfo userInfo = new UserInfo(userDTO.getId(), userDTO.getUsername(), "admin");
            //        生成私钥对象
//            PrivateKey privateKey = RsaUtils.getPrivateKey(privateKeyPath);
            PrivateKey privateKey = prop.getPrivateKey();
            //        生成Token
            String token = JwtUtils.generateTokenExpireInMinutes(userInfo, privateKey, prop.getUserToken().getExpire());
//        把Token返回给客户端,放在cookie
            CookieUtils.newCookieBuilder()
                    .name(prop.getUserToken().getCookieName())
                    .value(token)
                    .domain(prop.getUserToken().getCookieDomain())
                    .httpOnly(true)//为了当前cookie内容过的安全，不允许js操作，只能由http请求来操作
                    .response(response)
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
    }

    /**
     * 验证用户登录信息
     * @param request
     * @return
     */
    public UserInfo verify(HttpServletRequest request,HttpServletResponse response) {
        try{
//        从请求中获取token
            String token = CookieUtils.getCookieValue(request, prop.getUserToken().getCookieName());
//        生成公钥对象
//            PublicKey publicKey = RsaUtils.getPublicKey(publicKeyPath);
            PublicKey publicKey = prop.getPublicKey();
//            生成私钥对象
//            PrivateKey privateKey = RsaUtils.getPrivateKey(privateKeyPath);
            PrivateKey privateKey = prop.getPrivateKey();
//        解析token
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, publicKey, UserInfo.class);
//            获取jti
            String jti = payload.getId();
//            判断当前token是否已经被登出，到黑名单中验证
            Boolean b = redisTemplate.hasKey(jti);
            if(b){
//                返回true，说明当前token在黑名单中
                throw new LyException(ExceptionEnum.UNAUTHORIZED);
            }
            //        获取用户信息
            UserInfo userInfo = payload.getUserInfo();
//            获取token的过期时间
            Date expiration = payload.getExpiration();
//            使用joda计算最早的刷新token时间点
            DateTime dateTime = new DateTime(expiration).minusMinutes(1);
//          用当前时间和最早刷新时间比较，如果当前时间大于最早刷新时间点，刷新
            if(dateTime.isBeforeNow()){
//                所谓的刷新token，就是重新生成一个token
                token = JwtUtils.generateTokenExpireInMinutes(userInfo, privateKey, prop.getUserToken().getExpire());
//                把token写入cookie中
                CookieUtils.newCookieBuilder()
                        .name(prop.getUserToken().getCookieName())
                        .value(token)
                        .domain(prop.getUserToken().getCookieDomain())
                        .httpOnly(true)
                        .response(response)
                        .build();
            }
            return userInfo;
        }catch(Exception e){
            e.printStackTrace();
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
    }

    @Autowired
    private StringRedisTemplate redisTemplate;
    /**
     * 登出操作
     * 使用黑名单机制
     * @param request
     * @param response
     * @return
     */
    public void logout(HttpServletRequest request, HttpServletResponse response) {
        try{
//        获取token
            String token = CookieUtils.getCookieValue(request, prop.getUserToken().getCookieName());
//        生成公钥对象
//            PublicKey publicKey = RsaUtils.getPublicKey(publicKeyPath);
            PublicKey publicKey = prop.getPublicKey();
//        解析token
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, publicKey, UserInfo.class);
//        获取jwt的id,是当前jwt的唯一标识
            String jti = payload.getId();
//        获取token的过期时间
            Date expiration = payload.getExpiration();
//        计算当前token的剩余有效时间
            long time = expiration.getTime() - System.currentTimeMillis();
//        存储redis
            redisTemplate.opsForValue().set(jti,"1",time, TimeUnit.MILLISECONDS);
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            CookieUtils.deleteCookie(
                    prop.getUserToken().getCookieName(),
                    prop.getUserToken().getCookieDomain(),
                    response);
        }

    }
}
